I menù I menù costituiscono una parte vitale del sistema, un mezzo importante per l'iterazione con l'utente; i menù (non ci riferiamo naturalmente a quelli del ristorante) servono ad indicare all'applicazione di compiere determinate azioni, o ad indicare determinati attributi (ad esempio grandezza, tipo e caratteristiche di un font da una lista); le stesse operazioni possono essere svolte da una finestra o un requester con una serie di gadgets, ma il gran vantaggio dei menù risiede nel fatto che sono a scomparsa, vale a dire che le opzioni non vengono normalmente mostrate sullo schermo, ma vengono visualizzate solo con la pressione del stato destro del mouse. Una volta premuto il tasto destro, apparirà al posto della barra titolo dello schermo una prima lista di opzioni indicanti i titoli dei menù; una volta selezionato uno di questi titoli, apparirà un box con una lista di elementi; selezionando uno di questi e rilasciando il pulsante del mouse, si indica all'applicazione di aver selezionato l'opzione indicata; l'opzione può però possedere a sua volta una sotto lista, in tal caso selezionando l'opzione apparirà affianco un'altra lista dando la possibiltà di selezionare un opzione ad un livello successivo; gli elementi che indicano gli attribuiti vengono contraddistinti con un checkmark (di solito un'immagine a forma di v) se selezionati. Ogni finestra può avere un suo menù anche se vengono visualizzati nello stesso punto (se le finestre sono presenti sullo stesso schermo), dato che solo una finestra può essere quella attiva. Gli elementi dei menù sono costituiti a livello grafico da un testo, da un'immagine o da tutti e due insieme. La principale limitazione dei menù risiede nel numero di opzioni e di livelli utilizzabili; il numero di livelli utilizzabili è 3 (titoli menù, menù e sottomenù), ogni livello può possedere al massimo rispettivamente 31, 63 e 31 elementi. Per attivare un menù occorre utilizzare la funzione di Intuition: ris = SetMenuStrip(finestra,menu); dove finestra è il puntatore alla struttura Window della finestra in cui inserire il menù; menu è il puntatore alla struttura Menu contenente tutte le definizioni dei menù (vedremo fra breve come è strutturato); il valore ritornato "ris", è un BOOL che indica successo o fallimento; in realtà non può accadere che il menù non venga installato per cui la funzione ritorna sempre TRUE; la funzione invece per rimuovere un menù è: ClearMenuStrip(finestra); le due funzioni vanno chiamate all'inizio e all'uscita del programma (oppure nel momento in cui si decide di visualizzare e rimuovere il menù), ma comunque sempre dopo aver aperto la finestra e prima di chiuderla rispettivamente. Se si decide in un particolare momento, di cambiare la struttura del menù (opzioni visualizzate, disabilitate ecc.) occorre prima rimuovere il menù, effettuare le modifiche sulla relativa struttura, e riagganciare il menù alla finestra una volta effettuate tutte le modifiche; c'è la possibilità però di non usare necessariamente SetMenuStrip, se le modifiche effettuate sono solo l'abilitazione/disabilitazione di opzioni o la selezione/deselezione di attributi con checkmark; in tal caso la funzione utilizzabile per agganciare un menù (attenzione utilizzare solo se in passato è stata chiamata la funzione SetMenuStrip), che risulta essere molto più "leggera" è: ris = ResetMenuStrip(finestra,menu); dove i parametri passati e ricevuti ricoprono lo stesso significato prima descritto. Per disabilitare totalmente il menù (infatti anche quando nessun menù e agganciato, premendo il tasto destro appare la barra del menù), occorre specificare il flag WA_RMBTRAP nel tag WA_Flags di OpenWindowTagList(); questo flag non solo impedisce di visualizzare la barra titolo, ma permette anche di individuare la pressione del tasto destro, inviando un messaggio IDCMP_MOUSEBUTTONS. Una stessa struttura menù può essere condivisa ed utilizzata da più finestre, a condizione che le finestre siano presenti sullo stesso schermo; tenete presente che così facendo lo stesso menù apparirà per diverse finestre, a meno di non cambiarne la struttura all'attivazione di ognuna di queste (IDCMP_ACTIVEWINDOW); l'applicazione in tal caso deve anche attivare IDCMP_MENUVERIFY, in modo da impedire che l'utente utilizzi il menù di una finestra appena attivata, prima che l'applicazione abbia gestito l'evento IDCMP_ACTIVEWINDOW relativo. Una volta che l'utente rilascia un menù (anche senza aver selezionato alcuna opzione) il sistema invierà un messaggio di tipo IDCMP_MENUPICK; il codice dell'opzione eventualmente selezionata è presente nel campo Code della struttura IntuiMessage del messaggio di Intuition; il codice è di 16 bit ed è così suddiviso: i primi 5 bit (0-4) indicano il numero del menù, gli altri 6 bits (5-10) indicano il codice dell'opzione del menù e i restanti 5 bits (11-15) indicano il codice dell'opzione di un eventuale sotto-menù. Nel caso nessun opzione sia stata selezionata il valore Code, equivale ad una costante denominata MENUNULL; per prelevare i codici del menù, opzione e opzione del sotto-menù non è necessario andare ad esaminare direttamente i bit di Code, basta semplicemente utilizzare le seguenti macro sempre definite in "intuition/intuition.h": MENUNUM(Code) restituisce il numero del menù, ITEMNUM(Code) restituisce il numero dell'opzione, SUBNUM(Code) restituisce il numero dell'oipzione del sotto-menù; i valori restitui partono da 0 (primo menù o opzione), 1 (secondo menu' o opzione) e arrivano fino 30 o 62 (31-esima o 63-esima opzione o menù). Come ben sapete utilizzando quotidianamente Amiga, è possibile effettuare la multi-selezione nei menù; ciò significa che mentre gironzolo per i menù mantenendo premuto il tasto destro, posso selezionare più opzioni premendo il tasto sinistro; il sistema genererà in tal caso sempre un solo messaggio IDCMP_MENUPICK, ma come individuare tutte le opzioni selezionate allora? Il codice ritornato si riferisce ad uno degli elementi selezionati, nel campo NextSelect della struttura MenuItem dell'opzione relativa, s itroverà il codice di un'altra opzione selezionata, e così via fino a quando il campo NextSelect non vale MENUNULL; rimane a questo punto il problema di come determinare l'indirizzo di una struttura MenuItem partendo dal codice; il sistema ci viene in soccorso con la seguente funzione: Opzione = ItemAddress(menu,codicemenu); dove menu è il puntatore alla struttura Menu del menù, codice è il codice dell'opzione selezionata e Opzione è il puntatore alla struttura MenuItem dell'opzione relativa. Dopo quanto detto il ciclo di programma per l'esaminazione delle selezioni per i menù è il seguente: struct IntuiMessage *msg; struct Menu *menu; UWORD CodiceMenu; struct MenuItem *Opzione; . . CodiceMenu = msg -> Code; while (CodiceMenu != MENUNULL) { Opzione = ItemAddress(menu,CodiceMenu); /* processo l'attuale opzione */ CodiceMenu = Opzione -> NextSelect; } E' possibile dalla V37 del sistema far indicare se l'utente desidera avere delle informazioni sull'azione compiuta dall'opzione del menù; infatti l'utente mentre seleziona un'opzione del menù, può premere il tasto HELP; in tal caso il sistema si comporterà come se l'utente avesse effettivamente selezionato ma, invece di inviare un messaggio di tipo IDCMP_MENUPICK, ne invierà uno di tipo IDCMP_MENUHELP, e verrà passato nel campo Code il codice dell'opzione relativa; in questo caso l'applicazione (ciò non è ovviamente obbligatorio) dovrà visualizzare le informazioni di aiuto per quella opzione. Nell'inizializzazione delle strutture Menu e MenuItem, occorre indicare il box di selezione dell'opzione o del titolo del menù; bisogna far attenzione nel considerare la grandezza del font quando si decide la grandezza del box e inoltre, bisogna stare attenti (questo per versioni del sistema prima della V37) che i box di opzioni successive siano adiacenti; il box contenente le opzioni del menù verrà automaticamente dimensionato dal sistema ed il box del sotto-menù può sovrapporsi al box del menù; esiste in realtà un modo più semplice per realizzare menù e gadget ed è la gadtools.library che vedremo in una delle prossime puntate. Come abbiamo già detto le opzioni possono essere di tipo attributo; ciò vuol dire che un'opzione può essere selezionata o deselezionata indicando così uno stato (attivo o disattivo); per specificare che un'opzione è di tipo attributo bisogna indicare il flag CHECKIT nel campo Flags della relativa struttura MenuItem; se l'opzione è selezionata, verrà attivato il flag CHECKED sempre nel campo Flags. Normalmente quando si sceglie un'opzione attributo questa viene sempre selezionata, indipendentemente dallo stato in cui si trova; se si specifica il flag MENUTOGGLE verrà invertito lo stato attuale; è possibile effettuare la mutua-esclusione fra opzioni attributo, in maniera che selezionando un'opzione è possibile deselezionarne altre; ciò è reso possibile dal campo MutualExclude; questo è un campo di tipo LONG, in cui ogni bit rappresenta un'opzione (bit 0 prima opzione, bit 1 seconda opzione ecc.); al momento della selezione, le opzioni i cui rispettivi bit sono impostati ad uno verranno deselezionate. Vediamo un esempio per comprendere meglio questo meccanismo, supponiamo infatti di dover specificare mediante menù lo stile di un testo, i campi con i relativi valori di mutual-exclude saranno: Plain 0xFFFE Bold 0x0001 Italic 0x0001 Underline 0x0001 in tale maniera se seleziono Plain, resetterò tutte le altre opzioni fuorché se stessa (infatti tutti i bit con posizione maggiore di 0 sono impostati ad 1, mentre il bit 0 a 0); se seleziono Bold, Italic o Underline disattiverò solamente la prima opzione (Plain) in quanto solo il bit 0 è impostato a 1.